package cn.hashq.netpostclient.handler.proxy;

import cn.hashq.netpostclient.cache.ChannelCache;
import cn.hashq.netpostclient.dto.ProtoMsg;
import cn.hashq.netpostclient.handler.BaseHandler;
import cn.hashq.netpostclient.handler.ExceptionHandler;
import cn.hashq.netpostclient.handler.map.EmptyDecoder;
import cn.hashq.netpostclient.handler.map.EmptyEncoder;
import cn.hashq.netpostclient.handler.map.MapDataHandler;
import cn.hashq.netpostclient.util.NettyUtil;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

@Slf4j
@ChannelHandler.Sharable
public class ServerDataRedirectHandler extends BaseHandler {

    @Override
    public ProtoMsg.HeadType getHeadType() {
        return ProtoMsg.HeadType.SERVER_DATA_REDIRECT;
    }

    @Override
    public void process(ChannelHandlerContext ctx, ProtoMsg.Message msg) {
        String sessionId = msg.getSessionId();
        log.info("客户端收到服务端转发的数据,Session Id:{}", sessionId);
        Channel channel = ChannelCache.getInstance().getChannel(sessionId);
        ProtoMsg.DataPackage dataPackage = msg.getDataPackage();
        int clientPort = dataPackage.getClientPort();
        if (Objects.isNull(channel)) {
            connectLocalAppAndWriteMsg(msg, dataPackage, clientPort);
        } else {
            if (!channel.isActive()) {
                ChannelCache.getInstance().removeChannel(channel.id().asLongText());
                connectLocalAppAndWriteMsg(msg, dataPackage, clientPort);
            } else {
                channel.writeAndFlush(dataPackage.getBytes().toByteArray());
            }
        }
    }

    private void connectLocalAppAndWriteMsg(ProtoMsg.Message msg, ProtoMsg.DataPackage dataPackage, int clientPort) {
        ChannelInitializer<SocketChannel> channelInitializer = new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline()
                        .addLast(new EmptyEncoder())
                        .addLast(new EmptyDecoder())
                        .addLast(new MapDataHandler(msg.getSessionId()))
                        .addLast(new ExceptionHandler());
            }
        };
        GenericFutureListener listener = new GenericFutureListener() {
            @Override
            public void operationComplete(Future future) throws Exception {
                if (future.isSuccess()) {
                    log.info("连接本地端口{}成功", clientPort);
                } else {
                    log.error("连接本地端口{}失败,原因:{}", clientPort, future.cause().getMessage());
                }
            }
        };
        ChannelFuture future = NettyUtil.connectServer("localhost", clientPort, channelInitializer, listener);
        if (Objects.nonNull(future)) {
            log.info("向本地端口传递数据");
            ChannelCache.getInstance().addChannel(msg.getSessionId(), future.channel());
            future.channel().writeAndFlush(dataPackage.getBytes().toByteArray());
        } else {
            log.error("连接本地端口{}失败", clientPort);
        }
    }
}
